﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections;

namespace Blog.Core
{
    public abstract class BaseObjectCollection<T> : CollectionBase, IList<T>, IBindingList
        where T:BaseObject
    {
        private IList _list;
        private bool _loaded;
        private ListChangedEventArgs resetEvent = new ListChangedEventArgs(ListChangedType.Reset, -1);
        private ListChangedEventHandler onListChanged;
        private object _syncRoot = new object();

        public BaseObjectCollection()
        {
            _list = (IList)this;            
        }

        public IList<T> Load(bool reload = false)
        {
            if (reload)
            {
                _list.Clear();
                _loaded = false;
            }

            if (_loaded)
                return this;

            _loaded = true;
            LoadExecute();

            OnListChanged(resetEvent);
            return this;
        }

        protected abstract void LoadExecute();
        protected abstract T GenerateNewObject();

        public object AddNew()
        {
            T obj = GenerateNewObject();
            List.Add(obj);
            return obj;
        }

        protected override void OnInsertComplete(int index, object value)
        {
            T c = (T)value;
            c.Parent = this;
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
        }

        protected override void OnRemoveComplete(int index, object value)
        {
            T c = (T)value;
            c.Parent = this;
            c.SetDeleted();
            c.Save();
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
        }

        protected override void OnSetComplete(int index, object oldValue, object newValue)
        {
            if (oldValue != newValue)
            {
                T oldcust = (T)oldValue;
                T newcust = (T)newValue;

                oldcust.Parent = null;
                newcust.Parent = this;

                OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
            }
        }

        protected override void OnClearComplete()
        {
            OnListChanged(resetEvent);
        }

        public event ListChangedEventHandler ListChanged
        {
            add
            {
                onListChanged += value;
            }
            remove
            {
                onListChanged -= value;
            }
        }

        protected virtual void OnListChanged(ListChangedEventArgs ev)
        {
            if (onListChanged != null)
                onListChanged(this, ev);
        }

        public T this[int index]
        {
            get
            {
                return _list[index] as T;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public new IEnumerator<T> GetEnumerator()
        {
            return _list.OfType<T>().GetEnumerator();
        }

        public int IndexOf(T item)
        {
            return _list.IndexOf(item);
        }

        public void Insert(int index, T item)
        {
            throw new NotImplementedException();
        }

        public bool Contains(T item)
        {
            return _list.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            _list.CopyTo(array, arrayIndex);
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public void Add(T item)
        {
            List.Add(item);          
        }

        public bool Remove(T item)
        {
            List.Remove(item);
            return true;
        }

        public void AddIndex(PropertyDescriptor property)
        {
            throw new NotImplementedException();
        }

        public bool AllowEdit
        {
            get { return true; }
        }

        public bool AllowNew
        {
            get { return true; }
        }

        public bool AllowRemove
        {
            get { return true; }
        }

        public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
        {
            throw new NotImplementedException();
        }

        public int Find(PropertyDescriptor property, object key)
        {
            throw new NotImplementedException();
        }

        public bool IsSorted
        {
            get { throw new NotImplementedException(); }
        }

        public void RemoveIndex(PropertyDescriptor property)
        {
            throw new NotImplementedException();
        }

        public void RemoveSort()
        {
            throw new NotImplementedException();
        }

        public ListSortDirection SortDirection
        {
            get { return ListSortDirection.Ascending; }
        }

        public PropertyDescriptor SortProperty
        {
            get { throw new NotImplementedException(); }
        }

        public bool SupportsChangeNotification
        {
            get { return true; }
        }

        public bool SupportsSearching
        {
            get { return false; }
        }

        public bool SupportsSorting
        {
            get { return false; }
        }

        public int IndexOf(object value)
        {
            return _list.IndexOf(value);
        }

        public void Insert(int index, object value)
        {
            throw new NotImplementedException();
        }

        public bool IsFixedSize
        {
            get { return false; }
        }

        public void CopyTo(Array array, int index)
        {
            throw new NotImplementedException();
        }

        public bool IsSynchronized
        {
            get { return true; }
        }
       
        public object SyncRoot
        {
            get { return _syncRoot; }
        }
    }
}
